/* js lib wrapped the google maps v3 */

(function(global) {
    // Global namespace
    var gmap = gmap || {};
    // Google geocode function
    var geocoder = new google.maps.Geocoder();
    gmap.geocode = geocoder.geocode;

    /* An InfoBox is like an info window, but it displays
    * under the marker, opens quicker, and has flexible styling.
    * @param {GLatLng} latlng Point to place bar at
    * @param {Map} map The map on which to display this InfoBox.
    * @param {Object} opts Passes configuration options - content,
    *   offsetVertical, offsetHorizontal, className, height, width
    */
    function InfoBox(opts) {
      google.maps.OverlayView.call(this);
      this.latlng_ = opts.latlng;
      this.html = opts.html;
      this.map_ = opts.map;
      this.offsetVertical_ = -168;
      this.offsetHorizontal_ = 5;
      this.height_ = 165;
      this.width_ = 266;

      var me = this;
      this.boundsChangedListener_ =
      google.maps.event.addListener(this.map_, "bounds_changed", function() {
          return me.panMap.apply(me);
      });

      // Once the properties of this OverlayView are initialized, set its map so
      // that we can display it.  This will trigger calls to panes_changed and
      // draw.
      this.setMap(this.map_);
    }

    /* InfoBox extends GOverlay class from the Google Maps API
    */
    InfoBox.prototype = new google.maps.OverlayView();

    /* Creates the DIV representing this InfoBox
    */
    InfoBox.prototype.remove = function() {
      if (this.div_) {
        this.div_.parentNode.removeChild(this.div_);
        this.div_ = null;
      }
    };

    /* Redraw the Bar based on the current projection and zoom level
    */
    InfoBox.prototype.draw = function() {
      // Creates the element if it doesn't exist already.
      this.createElement();
      if (!this.div_) return;

      // Calculate the DIV coordinates of two opposite corners of our bounds to
      // get the size and position of our Bar
      var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
      if (!pixPosition) return;

      // Now position our DIV based on the DIV coordinates of our bounds
      this.div_.style.width = this.width_ + "px";
      this.div_.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
      this.div_.style.height = this.height_ + "px";
      this.div_.style.top = (pixPosition.y + this.offsetVertical_) + "px";
      this.div_.style.display = 'block';
    };

    /* Creates the DIV representing this InfoBox in the floatPane.  If the panes
    * object, retrieved by calling getPanes, is null, remove the element from the
    * DOM.  If the div exists, but its parent is not the floatPane, move the div
    * to the new pane.
    * Called from within draw.  Alternatively, this can be called specifically on
    * a panes_changed event.
    */
    InfoBox.prototype.createElement = function(html) {
      var panes = this.getPanes();
      var div = this.div_;
      if (!div) {
        // This does not handle changing panes.  You can set the map to be null and
        // then reset the map to move the div.
        div = this.div_ = document.createElement("div");
        div.style.border = "0px none";
        div.style.position = "absolute";
        div.style.background = "url('/static/img/info-window/blueinfowindow.gif')";
        div.style.width = this.width_ + "px";
        div.style.height = this.height_ + "px";
        var contentDiv = document.createElement("div");
        contentDiv.style.padding = "30px"
        contentDiv.innerHTML = this.html; //"<b>Hello World!</b>";

        var topDiv = document.createElement("div");
        topDiv.style.textAlign = "right";
        var closeImg = document.createElement("img");
        closeImg.style.width = "32px";
        closeImg.style.height = "32px";
        closeImg.style.cursor = "pointer";
        closeImg.src = "/static/img/info-window/closebigger.gif";
        topDiv.appendChild(closeImg);

        function removeInfoBox(ib) {
          return function() {
            ib.setMap(null);
          };
        }

        google.maps.event.addDomListener(closeImg, 'click', removeInfoBox(this));

        div.appendChild(topDiv);
        div.appendChild(contentDiv);
        div.style.display = 'none';
        panes.floatPane.appendChild(div);
        this.panMap();
      } else if (div.parentNode != panes.floatPane) {
        // The panes have changed.  Move the div.
        div.parentNode.removeChild(div);
        panes.floatPane.appendChild(div);
      } else {
        // The panes have not changed, so no need to create or move the div.
      }
    }

    /* Pan the map to fit the InfoBox.
    */
    InfoBox.prototype.panMap = function() {
      // if we go beyond map, pan map
      var map = this.map_;
      var bounds = map.getBounds();
      if (!bounds) return;

      // The position of the infowindow
      var position = this.latlng_;

      // The dimension of the infowindow
      var iwWidth = this.width_;
      var iwHeight = this.height_;

      // The offset position of the infowindow
      var iwOffsetX = this.offsetHorizontal_;
      var iwOffsetY = this.offsetVertical_;

      // Padding on the infowindow
      var padX = 40;
      var padY = 40;

      // The degrees per pixel
      var mapDiv = map.getDiv();
      var mapWidth = mapDiv.offsetWidth;
      var mapHeight = mapDiv.offsetHeight;
      var boundsSpan = bounds.toSpan();
      var longSpan = boundsSpan.lng();
      var latSpan = boundsSpan.lat();
      var degPixelX = longSpan / mapWidth;
      var degPixelY = latSpan / mapHeight;

      // The bounds of the map
      var mapWestLng = bounds.getSouthWest().lng();
      var mapEastLng = bounds.getNorthEast().lng();
      var mapNorthLat = bounds.getNorthEast().lat();
      var mapSouthLat = bounds.getSouthWest().lat();

      // The bounds of the infowindow
      var iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
      var iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
      var iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
      var iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * degPixelY;

      // calculate center shift
      var shiftLng =
      (iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) +
      (iwEastLng > mapEastLng ? mapEastLng - iwEastLng : 0);
      var shiftLat =
      (iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) +
      (iwSouthLat < mapSouthLat ? mapSouthLat - iwSouthLat : 0);

      // The center of the map
      var center = map.getCenter();

      // The new map center
      var centerX = center.lng() - shiftLng;
      var centerY = center.lat() - shiftLat;

      // center the map to the new shifted center
      map.setCenter(new google.maps.LatLng(centerY, centerX));

      // Remove the listener after panning is complete.
      google.maps.event.removeListener(this.boundsChangedListener_);
      this.boundsChangedListener_ = null;
    };

    gmap.InfoBox = InfoBox;

    ///////////////////////////////////////////////////////////////////////////
    // Marker Images                                                         //
    ///////////////////////////////////////////////////////////////////////////
    gmap.selfMarker = new google.maps.MarkerImage(
      '/static/img/marker/self.png',
      new google.maps.Size(38, 64),
      new google.maps.Point(0, 0),
      new google.maps.Point(19, 64)
    );

    gmap.homeMarker = new google.maps.MarkerImage(
      '/static/img/marker/home.png',
      new google.maps.Size(48, 48),
      new google.maps.Point(0, 0),
      new google.maps.Point(24, 48)
    );

    gmap.placeMarker = new google.maps.MarkerImage(
      '/static/img/marker/result.png',
      new google.maps.Size(36, 36),
      new google.maps.Point(0, 0),
      new google.maps.Point(18, 36)
    );

    ////////////////////////////////////////////////////////////////////////////
    // Methos                                                                 //
    ////////////////////////////////////////////////////////////////////////////
    gmap.getTaggedPhotos = function(map) {
      var panoramioLayer = new google.maps.panoramio.PanoramioLayer();
      panoramioLayer.setMap(map);

      var tagFilter = document.getElementById('search').value;
      panormaioLayer.setTag(tagFilter);
    };

    gmap.clearOverlays = function(markersArray) {
      if (markersArray) {
        for (i in markersArray) {
          markersArray[i].setMap(null);
        }
      }
    };

    // Deletes all markers in the array by removing references to them
    gmap.deleteOverlays = function(markersArray) {
      if (markersArray) {
        for (i in markersArray) {
          markersArray[i].setMap(null);
        }
        markersArray.length = 0;
      }
    };

    gmap.createPlacesMarker = function(map, data, index) {
      var image = '/static/img/marker/result' + (index ? (index + 1) : 1) + '.png',
      icon = new google.maps.MarkerImage(image,
        new google.maps.Size(32, 32),
        new google.maps.Point(0, 0),
        new google.maps.Point(16, 32)),  
        title = data.name, latlng, marker, html;

        html = utils.createInfoWindowHTML(data);

        latlng = new google.maps.LatLng(data.latitude, data.longitude);
        marker = new google.maps.Marker({
            position: latlng,
            title: title,
            map: map,
            icon: icon
        });


        google.maps.event.addListener(marker, "click", function(e) {
            marker.infoBox = new InfoBox({latlng: marker.getPosition(), map: map, html:html});
        });

        return marker;
      };

      gmap.createPlaceMarker = function(map, latlng, title) {
        var marker = new google.maps.Marker({
            position: latlng,
            title: title,
            map: map,
            icon: gmap.selfMarker
        });

        return marker;
      };                                                    

      gmap.createSelfMarker = function(map, latlng) {
        var marker = new google.maps.Marker({
            position: latlng,
            title: 'I am here',
            map: map,
            icon: gmap.selfMarker,
            draggable: true
        });

        return marker;
      };                              

      gmap.createHomeMarker = function(map, latlng) {
        var marker = new google.maps.Marker({
            position: latlng,
            title: 'This is my home',
            map: map,
            icon: gmap.homeMarker,
            draggable: true
        });

        return marker;
      };                                  

      // Get Bounds from a given placea array
      // currently this algorithms only suite for China.      
      gmap.createBounds = function(places) {
        var i, bounds,
            latitude, longitude, 
            swLatitude, swLongitude, 
            neLatitude, neLongitude;

        minLatitude = maxLatitude = parseFloat(places[0].latitude, 10);
        minLongitude = maxLongitude = parseFloat(places[0].longitude, 10);

        console.log('init is: ' + minLatitude + ', ' + minLongitude);
        for (i = 1; i < places.length; i++) {
          latitude = parseFloat(places[i].latitude, 10);
          longitude = parseFloat(places[i].longitude, 10);

          console.log('latitude: ' + latitude);
          console.log('longitude:' + longitude);

          if (latitude < minLatitude && longitude < minLongitude) {
            minLatitude = latitude;
            minLongitude = longitude;
          } else if (latitude > maxLatitude && longitude > maxLongitude) {
            maxLatitude = latitude;
            maxLongitude = longitude;
          } else if (latitude > maxLatitude && longitude < minLongitude) {
            maxLatitude = latitude;
            minLongitude = longitude;
          } else if (latitude < minLatitude && longitude > maxLongitude) {
            console.log('in.........');
            minLatitude = latitude;
            maxLongitude = longitude;
          } else if (latitude > maxLatitude) {
            maxLatitude = latitude;
          } else if (longitude > maxLongitude) {
            maxLongitude = longitude;
          } else if (latitude < minLatitude) {
            minLatitude = latitude;
          } else if (longitude < minLongitude) {
            minLongitude = longitude;
          } else {
            // pass
          }

        console.log('mininum is: ' + minLatitude + ', ' + minLongitude);
        console.log('maxinum is: ' + maxLatitude + ', ' + maxLongitude);       
        }

        console.log('mininum is: ' + minLatitude + ', ' + minLongitude);
        console.log('maxinum is: ' + maxLatitude + ', ' + maxLongitude);

        swLatLng = new google.maps.LatLng(minLatitude, minLongitude);
        neLatLg = new google.maps.LatLng(maxLatitude, maxLongitude);

        bounds = new google.maps.LatLngBounds(swLatLng, neLatLg);

        return bounds;
      };

      global.gmap = gmap;

  })(window);
